/*
 * Copyright (c) 2013 - 2015, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "app_inc.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define APP_DMA_XFER_BUF_COUNT  16U
#define APP_DMA_XFER_CHANNEL_IDX   0U
#define APP_DMA_CLEAR_CHANNEL_IDX  1U

/*******************************************************************************
 * Variables
 ******************************************************************************/

uint32_t gAppDmaBufferFrom[APP_DMA_XFER_BUF_COUNT];
uint32_t gAppDmaBufferTo[APP_DMA_XFER_BUF_COUNT];
uint32_t gAppDmaTransferDescripterBuffer[sizeof(DMA_TransferDescriptor_T) * 20U + 16U];
DMA_TransferDescriptor_T *gDmaTransferDescriptorBase;


volatile uint32_t gAppDmaClearWord = 0xFFFFFFFF; /* 清空PINT3的标志位 */
volatile uint32_t gAppDmaClearWordRx = 0U;


volatile uint32_t gPintCounter;

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void DMA_Configuration(void);
void PINT_Configuration(void);

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{
    char ch;
    uint32_t i;
    uint32_t oldPingCounter;

    gDmaTransferDescriptorBase = (DMA_TransferDescriptor_T *)((((uint32_t)gAppDmaTransferDescripterBuffer)+16U) & ~(0xF));

    /* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_BootClockRUN();

    /* Initialize debug console. */
    BOARD_InitDebugConsole(); /* Flexcomm0 - UART0, 115200. */

    PRINTF("\r\nDMA Software Trigger Example.\r\n");
    PRINTF("build time: %s, %s\r\n", __TIME__, __DATE__);

    /* Prepare the buffers. */
    for (i = 0U; i < APP_DMA_XFER_BUF_COUNT; i++)
    {
        gAppDmaBufferFrom[i] = i+1;
        gAppDmaBufferTo[i] = 0U;
    }

    DMA_Configuration();
    PINT_Configuration();

    gPintCounter = 0U;
    oldPingCounter = gPintCounter;
    while (1)
    {
        if (oldPingCounter != gPintCounter)
        {
            PRINTF("PINT Counter: %d\r\n", gPintCounter);
            oldPingCounter = gPintCounter;
        }
    }
}

DMA_TransferDescriptor_T * volatile gDmaRamDescriptorTable;

void DMA_Configuration(void)
{
    DMA_ChannelConfig_T DmaChannelConfigStruct = {0U};
    DMA_TransferConfig_T DmaTransferConfigStruct = {0U};
    DMA_BurstTransferConfig_T DmaBurstTransferConfigStruct;

    uint32_t xfercfg;

    CLOCK_EnableClock(kCLOCK_Dma);

    DMA_Init(DMA0);
    gDmaRamDescriptorTable = (DMA_TransferDescriptor_T * )(DMA0->SRAMBASE);

    DMA_EnableChannels(DMA0, (1U<<APP_DMA_XFER_CHANNEL_IDX) | (1U << APP_DMA_CLEAR_CHANNEL_IDX) , true);


/* 配置传输通道 */
    DmaChannelConfigStruct.EnablePeripheralRequest = false;
    DmaChannelConfigStruct.EnableHardwareTrigger = true; /* Enable hardware trigger. */
    DmaChannelConfigStruct.HardwareTriggerMode = eDMA_HardwareTriggerMode_RisingEdge;
    DmaChannelConfigStruct.ChannelPriority = 0U; /* 最高优先级 */

    DmaBurstTransferConfigStruct.BurstTransferSizePower = 0U;
    DmaBurstTransferConfigStruct.EnableSourceBurstWrap = false;
    DmaBurstTransferConfigStruct.EnableDestBurstWrap = false;

    DmaChannelConfigStruct.BurstTransferConfig = &DmaBurstTransferConfigStruct;
    DMA_SetChannelConfig(DMA0, APP_DMA_XFER_CHANNEL_IDX, &DmaChannelConfigStruct);

    DmaTransferConfigStruct.EnableValidNow = true;
    DmaTransferConfigStruct.EnableReloadNextDescriptor = true; /* Reload the next descriptor when done. */
    DmaTransferConfigStruct.EnableTriggerBySoftwareNow = false;
    DmaTransferConfigStruct.EnableAutoClearTrigger = false; /* 在描述符耗尽之后，不自动关闭Trigger，从而可以继续Trigger下一个描述符. */
    DmaTransferConfigStruct.EnableFlagOnInterruptA = false; /* Enable the interrupt A. */
    DmaTransferConfigStruct.EnableFlagOnInterruptB = false;
    DmaTransferConfigStruct.TransferWidth = eDMA_TransferWidth_32b;
    DmaTransferConfigStruct.TransferSourceAddressIncrease = eDMA_TransferAddressIncrease_1xWidth;
    DmaTransferConfigStruct.TransferDestAddressIncrease = eDMA_TransferAddressIncrease_1xWidth;
    DmaTransferConfigStruct.TransferCount = APP_DMA_XFER_BUF_COUNT/2U-1;
    xfercfg = DMA_CreateTransferConfigWord(&DmaTransferConfigStruct);

    /* Add the first transfer descriptor. */
    gDmaTransferDescriptorBase[0].TransferConfigWord = xfercfg;
    gDmaTransferDescriptorBase[0].SourceEndAddrress = (uint32_t)&gAppDmaBufferFrom[APP_DMA_XFER_BUF_COUNT/2U-1U];
    gDmaTransferDescriptorBase[0].DestEndAddress = (uint32_t)&gAppDmaBufferTo[APP_DMA_XFER_BUF_COUNT/2U-1U];
    gDmaTransferDescriptorBase[0].LinkToNext = 0U;
    DMA_SetHeadTransferDescriptor(DMA0, APP_DMA_XFER_CHANNEL_IDX, &gDmaTransferDescriptorBase[0]);

    /* Add the second transfer descriptor, only change the addresses. */
    gDmaTransferDescriptorBase[1].TransferConfigWord = xfercfg;
    gDmaTransferDescriptorBase[1].SourceEndAddrress = (uint32_t)&gAppDmaBufferFrom[APP_DMA_XFER_BUF_COUNT-1];
    gDmaTransferDescriptorBase[1].DestEndAddress = (uint32_t)&gAppDmaBufferTo[APP_DMA_XFER_BUF_COUNT-1];
    gDmaTransferDescriptorBase[1].LinkToNext = 0U;
    DMA_AddTransferDescriptor(DMA0, APP_DMA_XFER_CHANNEL_IDX, &gDmaTransferDescriptorBase[1]);

#if 0
/* 配置自动清零通道。 */
    DmaChannelConfigStruct.EnablePeripheralRequest = false;
    DmaChannelConfigStruct.EnableHardwareTrigger = true; /* Enable hardware trigger. */
    DmaChannelConfigStruct.HardwareTriggerMode = eDMA_HardwareTriggerMode_RisingEdge;
    DmaChannelConfigStruct.ChannelPriority = 1U; /* 较低优先级 */

    DmaBurstTransferConfigStruct.BurstTransferSizePower = 0U;
    DmaBurstTransferConfigStruct.EnableSourceBurstWrap = true;
    DmaBurstTransferConfigStruct.EnableDestBurstWrap = true;

    DmaChannelConfigStruct.BurstTransferConfig = &DmaBurstTransferConfigStruct;
    DMA_SetChannelConfig(DMA0, APP_DMA_CLEAR_CHANNEL_IDX, &DmaChannelConfigStruct);

#if 1
    DmaTransferConfigStruct.EnableValidNow = true;
    DmaTransferConfigStruct.EnableReloadNextDescriptor = true; /* Reload the next descriptor when done. */
    DmaTransferConfigStruct.EnableTriggerBySoftwareNow = false;
    DmaTransferConfigStruct.EnableAutoClearTrigger = false; /* 在描述符耗尽之后，不自动关闭Trigger，从而可以继续Trigger下一个描述符. */
    DmaTransferConfigStruct.EnableFlagOnInterruptA = false; /* Enable the interrupt A. */
    DmaTransferConfigStruct.EnableFlagOnInterruptB = false;
    DmaTransferConfigStruct.TransferWidth = eDMA_TransferWidth_32b;
    DmaTransferConfigStruct.TransferSourceAddressIncrease = eDMA_TransferAddressIncrease_1xWidth;
    DmaTransferConfigStruct.TransferDestAddressIncrease = eDMA_TransferAddressIncrease_1xWidth;
    DmaTransferConfigStruct.TransferCount = 0U;
    xfercfg = DMA_CreateTransferConfigWord(&DmaTransferConfigStruct);
#endif
    /* Add the first transfer descriptor. */
    gDmaTransferDescriptorBase[2].TransferConfigWord = xfercfg;
    gDmaTransferDescriptorBase[2].SourceEndAddrress = ((uint32_t)&gAppDmaClearWord);
    //gDmaTransferDescriptorBase[2].DestEndAddress = ((uint32_t)&(PINT->IST)) -4U;
    gDmaTransferDescriptorBase[3].DestEndAddress = ((uint32_t)&gAppDmaClearWordRx);
    gDmaTransferDescriptorBase[2].LinkToNext = &gDmaTransferDescriptorBase[3];
    DMA_SetHeadTransferDescriptor(DMA0, APP_DMA_CLEAR_CHANNEL_IDX, &gDmaTransferDescriptorBase[2]);

    gDmaTransferDescriptorBase[3].TransferConfigWord = xfercfg;
    gDmaTransferDescriptorBase[3].SourceEndAddrress = ((uint32_t)&gAppDmaClearWord);
    //gDmaTransferDescriptorBase[3].DestEndAddress = ((uint32_t)&(PINT->IST)) -4U;
    gDmaTransferDescriptorBase[3].DestEndAddress = ((uint32_t)&gAppDmaClearWordRx);
    gDmaTransferDescriptorBase[3].LinkToNext = &gDmaTransferDescriptorBase[2];
    //DMA_SetHeadTransferDescriptor(DMA0, APP_DMA_CLEAR_CHANNEL_IDX, &gDmaTransferDescriptorBase[3]);
#endif


    DMA_EnableChannelsInterruptOnTransferDone(DMA0,
        (1U << APP_DMA_XFER_CHANNEL_IDX) | (1U << APP_DMA_CLEAR_CHANNEL_IDX),
        true);


    NVIC_EnableIRQ(DMA0_IRQn);

    /* Setup the hardware trigger. */
    INPUTMUX_AttachSignal(INPUTMUX, APP_DMA_XFER_CHANNEL_IDX, kINPUTMUX_PinInt3ToDma);
    //INPUTMUX_AttachSignal(INPUTMUX, APP_DMA_CLEAR_CHANNEL_IDX, kINPUTMUX_PinInt3ToDma);
}

void pint3_intr_callback(pint_pin_int_t pintr, uint32_t pmatch_status)
{
    gPintCounter++;
}


void PINT_Configuration(void)
{
    PINT_Init(PINT);
    PINT_PinInterruptConfig(PINT, kPINT_PinInt3,
        kPINT_PinIntEnableRiseEdge, /* 上边沿均可触发 */
        pint3_intr_callback /* 注册触发时执行的函数 */
        );

    //PINT_EnableCallback(PINT); /* Enable callbacks for PINT */
    //NVIC_DisableIRQ(PIN_INT3_IRQn);

}

void DMA0_IRQHandler(void)
{
    uint32_t flagsA = DMA_GetChannelsOnInterruptA(DMA0);
    uint32_t flagsB = DMA_GetChannelsOnInterruptB(DMA0);

    DMA_ClearFlagsOnInterruptA(DMA0, flagsA);
    DMA_ClearFlagsOnInterruptB(DMA0, flagsB);
}

/* EOF. */
